﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="OleDatabaseHelper.cs" company="CodePlex">
//   Copyright © CodePlex 2012
// </copyright>
// <summary>
//   Defines the OleDatabaseHelper type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace DataFramework
{
    using System;
    using System.Data;
    using System.Data.OleDb;

    using DataFramework.Interfaces;

    /// <summary>
    /// Database helper that provides Ole DB adapter specific functionality to query building utilities.
    /// </summary>
    internal class OleDatabaseHelper : IDatabaseHelper
    {
        /// <summary>
        /// Gets the query parameter prefix.
        /// </summary>
        /// <value>The query parameter prefix.</value>
        public char QueryParameterPrefix
        {
            get
            {
                return '?';
            }
        }

        /// <summary>
        /// Creates the parameter.
        /// </summary>
        /// <param name="columnName">Name of the column.</param>
        /// <param name="columnType">Type of the column.</param>
        /// <param name="value">The value.</param>
        /// <returns>An object that implements the IDataParameter interface.</returns>
        public IDataParameter CreateParameter(string columnName, DbType columnType, object value)
        {
            IDataParameter parm;
            switch (DatabaseConfiguration.DbType)
            {
                case DatabaseType.OleDb:
                    value = this.ConvertValueToDbSafeValue(value);

                    if (columnType == DbType.Date && value is DateTime)
                    {
                        value = ((DateTime)value).Date;
                    }

                    parm = new OleDbParameter(columnName, ConvertDbTypeToNativeDbType(columnType)) { Value = value };
                    break;
                default:
                    throw new NotImplementedException();
            }

            return parm;
        }

        /// <summary>
        /// Converts the value to a database safe value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>A value safe to send to a OLE compatible database.</returns>
        public object ConvertValueToDbSafeValue(object value)
        {
            if (value != null && value.GetType().IsEnum)
            {
                value = (int)value;
            }

            return value ?? DBNull.Value;
        }

        /// <summary>
        /// Converts the type of the db type to native db.
        /// </summary>
        /// <param name="type">Type of the db.</param>
        /// <returns>a database type for the provided type.</returns>
        private static OleDbType ConvertDbTypeToNativeDbType(DbType type)
        {
            OleDbType returnType;

            switch (type)
            {
                case DbType.Binary:
                    returnType = OleDbType.Binary;
                    break;
                case DbType.Boolean:
                    returnType = OleDbType.Boolean;
                    break;
                case DbType.Byte:
                    returnType = OleDbType.UnsignedTinyInt;
                    break;
                case DbType.Currency:
                    returnType = OleDbType.Decimal;
                    break;
                case DbType.Date:
                    returnType = OleDbType.Date;
                    break;
                case DbType.DateTime:
                    returnType = OleDbType.DBTimeStamp;
                    break;
                case DbType.Decimal:
                    returnType = OleDbType.Decimal;
                    break;
                case DbType.Guid:
                    returnType = OleDbType.Guid;
                    break;
                case DbType.Int16:
                    returnType = OleDbType.SmallInt;
                    break;
                case DbType.Int32:
                    returnType = OleDbType.Integer;
                    break;
                case DbType.Int64:
                    returnType = OleDbType.BigInt;
                    break;
                case DbType.Single:
                    returnType = OleDbType.Single;
                    break;
                case DbType.String:
                    returnType = OleDbType.VarChar;
                    break;
                case DbType.StringFixedLength:
                    returnType = OleDbType.Char;
                    break;
                case DbType.Time:
                    returnType = OleDbType.DBTime;
                    break;
                default:
                    throw new ArgumentException(
                        string.Format("Parameter type not supported. {0}", Enum.GetName(type.GetType(), type)),
                        "type");
            }

            return returnType;
        }
    }
}